/* 
 * Copyright 2007 Parabon Computation, Inc.
 * 
 * Parabon Computation, Inc, grant you ("Licensee") a non-exclusive, royalty 
 * free, license to use, and redistribute this software in source and binary 
 * code form, provided that i) this copyright notice and license appear on 
 * all copies of the software; ii) Licensee does not utilize the software in 
 * a manner which is disparaging to Parabon and iii) Licensee does NOT 
 * modify the software in any way. 
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL 
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. PARABON AND ITS LICENSORS SHALL NOT 
 * BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, 
 * MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT 
 * WILL PARABON OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 
 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE 
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, 
 * ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF PARABON HAS 
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
 * 
 * This software is not designed or intended for use in on-line control of 
 * aircraft, air traffic, aircraft navigation or aircraft communications; or 
 * in the design, construction, operation or maintenance of any nuclear 
 * facility. Licensee represents and warrants that it will not use or 
 * redistribute the Software for such purposes. 
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.File;
import java.io.InputStream;
import java.io.FileOutputStream;

import com.parabon.client.SerializableTask;
import com.parabon.client.SerializableTaskContext;
import com.parabon.runtime.DataBuffer;
import com.parabon.runtime.TaskStoppedException;

/**
 * Computes the square of a single input. The square is computed using an
 * external native program that is passed in as a native data element.
 */
public class NativeTask implements SerializableTask {

  public static class Result implements Serializable {
    private static final long serialVersionUID = -1;

    private int square;

    public Result(int square) {
      this.square = square;
    }

    public double getSquare() {
      return square;
    }
  }

  private static final long serialVersionUID = -1;

  private static String workingDirectory = System.getProperty("tmpdir", ".");

  private DataBuffer data;

  private String inFileName;

  private int num;

  public NativeTask(DataBuffer data, String inFileName, int num) {
    this.data = data;
    this.inFileName = inFileName;
    this.num = num;
  }

  public Result run(SerializableTaskContext context)
	throws TaskStoppedException, InterruptedException, IOException {

    // Set the path to the native executable
    String inFilePath = workingDirectory + File.separator+inFileName;

    // Write square native executable to the task temporary directore
    writeDataElementToFile( inFilePath );

    // See if we have been asked to stop
    if(context.shouldStop()) {
      throw new TaskStoppedException();
    }
     
    // Compute the square
    int square = doSquare( inFilePath, num );

    // Return the final status (with the result)
    return new Result(square);
  }

  int doSquare (String exePath, int num) 
	throws IOException, InterruptedException {
    // Setup and launch the native executable
    Process pr=null;
			Runtime runtime = Runtime.getRuntime();
				try{
					pr=runtime.exec("chmod +x"+" "+exePath);
					
				}catch(Exception e){
					System.out.println("exception occured:"+e);
				}
	
				

    ProcessBuilder pb = new ProcessBuilder( exePath, Integer.toString( num ));
    pb.directory( new File( workingDirectory ) );
    Process p = pb.start();

    // Wait for the process to exit
    int exitVal = p.waitFor();
    if ( exitVal != 0 ) {
      throw new IOException ( "square process reported an illegal argument" );
    }
     
    // Read the result from stdout
    InputStream processInputStream = p.getInputStream();
    BufferedReader input =
      new BufferedReader (new InputStreamReader( processInputStream ));
    String line = input.readLine();
    if ( line == null ) {
      throw new IOException ( "square process didn't return a result." );
    }

    // Parse the result
    int res = 0;
    try {
      res = Integer.parseInt( line );
    }
    catch (NumberFormatException  err) {
      throw new IOException ( "square process returned an invalid result." );
    }

    // Cleanup and return
    input.close();

    return res;
  }

  private void writeDataElementToFile( String filePath ) 
    throws java.io.IOException {

    // Point a reader at the DataElement stream
    InputStream is = data.getInputStream();
    FileOutputStream os = new FileOutputStream( new File( filePath ) );

    byte[] buf = new byte[1024];
    int i = 0;
    while((i=is.read(buf))!=-1) {
      os.write(buf, 0, i);
    }
    os.close();
  }

  public void stop() {}
}
